package com.chenxinzhimusic.service

import android.R
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.IBinder
import android.provider.MediaStore
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import io.ktor.client.HttpClient
import io.ktor.client.engine.android.Android
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsChannel
import io.ktor.http.contentLength
import io.ktor.utils.io.jvm.javaio.toInputStream
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable.isActive
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.coroutines.cancellation.CancellationException

class DownloadService : Service() {
    private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
    private val channelId = "download_channel"
    private var isForegroundStarted = false

    override fun onCreate() {
        super.onCreate()
        createNotificationChannel()
    }

    @RequiresApi(Build.VERSION_CODES.Q)
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val url = intent?.getStringExtra("url") ?: return START_NOT_STICKY
        val fileName = intent.getStringExtra("fileName") ?: "music.mp3"
        Toast.makeText(this, "开始下载$fileName", Toast.LENGTH_SHORT).show()

        val key = "$url|$fileName"
        val notificationId = fileName.hashCode()

        if (!isForegroundStarted) {
            startForeground(notificationId, buildNotification("下载 $fileName", 0), ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK)
            isForegroundStarted = true
        }

        val job = scope.launch {
            try {
                downloadFileToMediaStore(url, fileName, notificationId)
            } catch (e: CancellationException) {
                updateNotification("已暂停：$fileName", 0, notificationId, completed = true)
            } finally {
                DownloadManager.cancel(key)
            }
        }

        DownloadManager.addJob(key, job)
        return START_NOT_STICKY
    }

    private suspend fun downloadFileToMediaStore(
        url: String,
        fileName: String,
        notificationId: Int
    ) = coroutineScope {
        val client = HttpClient(Android)
        val response = client.get(url)

        val totalBytes = response.contentLength() ?: return@coroutineScope
        val inputStream = response.bodyAsChannel().toInputStream()

        val uri = insertIntoMediaStore(fileName) ?: return@coroutineScope

        contentResolver.openOutputStream(uri)?.use { outputStream ->   // outputStream自动关闭
            inputStream.use { input ->    // inputStream自动关闭
                val buffer = ByteArray(8 * 1024)
                var bytesRead = 0L
                var read: Int

                while (input.read(buffer).also { read = it } != -1 && isActive) {
                    outputStream.write(buffer, 0, read)
                    bytesRead += read
                    val progress = (bytesRead * 100 / totalBytes).toInt()
                    updateNotification("下载中：$fileName", progress, notificationId)
                }
                outputStream.flush()
            }
        }
        withContext(Dispatchers.Main) { Toast.makeText(this@DownloadService, "下载完成$fileName", Toast.LENGTH_SHORT).show() }
        updateNotification("下载完成：$fileName", 100, notificationId, completed = true)

    }


    private fun insertIntoMediaStore(fileName: String): Uri? {
        val contentValues = ContentValues().apply {
            put(MediaStore.Audio.Media.DISPLAY_NAME, fileName)
            put(MediaStore.Audio.Media.MIME_TYPE, "audio/mpeg")
            put(MediaStore.Audio.Media.RELATIVE_PATH, Environment.DIRECTORY_MUSIC + "/musicCxz") // 音频专用目录
            put(MediaStore.Audio.Media.IS_MUSIC, true)
        }
        return contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, contentValues)
    }

    private fun buildNotification(
        title: String,
        progress: Int,
        completed: Boolean = false
    ): Notification {
        return NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.stat_sys_download)
            .setContentTitle(title)
            .setContentText(if (completed) "下载完成" else "$progress%")
            .setProgress(100, progress, false)
            .setOnlyAlertOnce(true)
            .setOngoing(!completed)
            .build()
    }

    private fun updateNotification(
        title: String,
        progress: Int,
        notificationId: Int,
        completed: Boolean = false
    ) {
        val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        manager.notify(notificationId, buildNotification(title, progress, completed))
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel =
                NotificationChannel(channelId, "歌曲下载", NotificationManager.IMPORTANCE_LOW)
            val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }
    }

    override fun onBind(intent: Intent?): IBinder? = null
}
fun Context.startDownloadService(url: String, fileName: String) {
    val intent = Intent(this, DownloadService::class.java).apply {
        putExtra("url", url)
        putExtra("fileName", fileName)
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(intent)
    } else {
        startService(intent)
    }
}

fun pauseDownload(url: String, fileName: String) {
    val key = "$url|$fileName"
    DownloadManager.pause(key)
}

fun cancelDownload(url: String, fileName: String) {
    val key = "$url|$fileName"
    DownloadManager.cancel(key)
}
